package com.pactera.madp.cp.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mysql.cj.util.StringUtils;
import com.pactera.madp.common.core.util.R;
import com.pactera.madp.common.data.tenant.TenantContextHolder;
import com.pactera.madp.cp.api.dto.daily.DailySendDTO;
import com.pactera.madp.cp.api.entity.WorkContactEmployeeEntity;
import com.pactera.madp.cp.api.entity.WorkContactRoomEntity;
import com.pactera.madp.cp.api.entity.WorkEmployeeEntity;
import com.pactera.madp.cp.api.entity.WorkRoomEntity;
import com.pactera.madp.cp.api.entity.daily.WorkContactDailyEntity;
import com.pactera.madp.cp.api.entity.daily.WorkContactRoomDailyEntity;
import com.pactera.madp.cp.api.entity.daily.WorkDailySendEntity;
import com.pactera.madp.cp.api.entity.employeeWechat.EmployeeDoEntity;
import com.pactera.madp.cp.api.model.workcontact.WorkContactDailyIndexResp;
import com.pactera.madp.cp.api.model.workroom.WorkContactRoomDailyIndexResp;
import com.pactera.madp.cp.api.util.Day;
import com.pactera.madp.cp.api.vo.daily.DailyIndexVo;
import com.pactera.madp.cp.api.vo.daily.DailyRespVo;
import com.pactera.madp.cp.api.vo.employee.EmployeeDoVO;
import com.pactera.madp.cp.common.util.wm.WorkMsgHelper;
import com.pactera.madp.cp.config.ConstantConfig;
import com.pactera.madp.cp.handler.CorpContextHolder;
import com.pactera.madp.cp.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZoneOffset;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class DailyServiceImpl implements DailyService {

    @Autowired
    private IWorkDailySendService workDailySendService;
    @Autowired
    private IWorkContactRoomDailyService workContactRoomDailyService;
    @Autowired
    private IWorkContactDailyService workContactDailyService;
    @Autowired
    private IWorkContactEmployeeService workContactEmployeeService;
    @Autowired
    private IWorkRoomService workRoomService;
    @Autowired
    private IWorkContactRoomService workContactRoomService;
    @Autowired
    private IWorkEmployeeService workEmployeeService;
    @Autowired
    private IWorkMsgService workMsgService;
    @Autowired
    private EmployeeDoService employeeDoService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public R generate(Integer corpId, Integer dailyType, Day day) {
        // 判定时间是生成数据
        // 每天23点定时任务，1，每天生成当日的，日报（当天），2，周报（获取本周第一天）3，月报(获取当月第一天）

        LocalDate localDate;
        if (dailyType == 2) {
            //本周第一天（外国的每周第一天是周天，这里写2)
            localDate = day.getFirstDayOfWeek();
        } else if (dailyType == 3) {
            // 本月第一天
            localDate = day.getFirstDayOfMonth();
        } else {
            localDate = LocalDate.now();
        }

        //得到时间
        String str;
        int size1 = workContactDailyService.lambdaQuery().eq(WorkContactDailyEntity::getCreateDay, localDate).eq(WorkContactDailyEntity::getDailyType, dailyType).count();
        int size2 = workContactRoomDailyService.lambdaQuery().eq(WorkContactRoomDailyEntity::getCreateDay, localDate).eq(WorkContactRoomDailyEntity::getDailyType, dailyType).count();

        if (size1 != 0 & size2 != 0) {
            str = "今天已经生成过客户日报和客群日报";
        } else if (size1 != 0 & size2 == 0) {
            workContactRoomDailyService.contactRoomDailyGenerate(corpId,dailyType, day);
            str = "今天已经生成过客户日报";
        } else if (size1 == 0 & size2 != 0) {
            workContactDailyService.contactDailyGenerate(corpId,dailyType, day);
            str = "今天已经生成过客群日报";
        } else {
            workContactRoomDailyService.contactRoomDailyGenerate(corpId,dailyType, day);
            workContactDailyService.contactDailyGenerate(corpId,dailyType, day);
            str = "生成成功";
        }

        return R.ok(str);
    }

    @Override
    public R reminder(Integer corpId, Integer type) {
        WorkDailySendEntity one = null;
        List<WorkDailySendEntity> list = workDailySendService.lambdaQuery().eq(WorkDailySendEntity::getCorpId, corpId).list();
        if (list.size() == 0) {
            return null;
        } else {
            one = list.get(0);
            if (!one.isOrder()) {
                return R.ok("");
            }
        }
        if (type == 1) {
            return this.dailyReminder(corpId, one);
        } else if (type == 2) {
            return this.weeklyReminder(corpId, one);
        } else if (type == 3) {
            return this.monthlyReminder(corpId, one);
        }
        return R.failed();
    }

    public R dailyReminder(Integer corpId, WorkDailySendEntity one) {
        DailyRespVo vo = new DailyRespVo();
        String daily = null;
        if (one.isDaily()) {
            List<WorkContactDailyEntity> contactEntity = workContactDailyService.lambdaQuery().eq(WorkContactDailyEntity::getCorpId, corpId)
                    .eq(WorkContactDailyEntity::getDailyType, 1)
                    .orderByDesc(WorkContactDailyEntity::getCreateTime).last("limit 1").list();

            if (contactEntity.size() == 0) {
                return R.ok("");
            }

            WorkContactDailyEntity contact = contactEntity.get(0);

            WorkContactRoomDailyEntity room = workContactRoomDailyService.lambdaQuery().eq(WorkContactRoomDailyEntity::getCorpId, corpId)
                    .eq(WorkContactRoomDailyEntity::getDailyType, 1)
                    .orderByDesc(WorkContactRoomDailyEntity::getCreateTime).last("limit 1").list().get(0);
            generate(one,contact, room, vo, 1);
            daily = change(vo, 1);
        }

        return R.ok(daily);
    }

    public R weeklyReminder(Integer corpId, WorkDailySendEntity one) {
        DailyRespVo vo = new DailyRespVo();

        String weekly = null;
        if (one.isWeekly()) {
            List<WorkContactDailyEntity> contactEntity = workContactDailyService.lambdaQuery().eq(WorkContactDailyEntity::getCorpId, corpId)
                    .eq(WorkContactDailyEntity::getDailyType, 2)
                    .orderByDesc(WorkContactDailyEntity::getCreateTime).last("limit 1").list();

            if (contactEntity.size() == 0) {
                return R.ok("");
            }

            WorkContactDailyEntity contact = contactEntity.get(0);

            WorkContactRoomDailyEntity room = workContactRoomDailyService.lambdaQuery().eq(WorkContactRoomDailyEntity::getCorpId, corpId)
                    .eq(WorkContactRoomDailyEntity::getDailyType, 2)
                    .orderByDesc(WorkContactRoomDailyEntity::getCreateTime).last("limit 1").list().get(0);
            generate(one,contact, room, vo, 2);
            weekly = change(vo, 2);
        }

        return R.ok(weekly);
    }

    public R monthlyReminder(Integer corpId, WorkDailySendEntity one) {
        DailyRespVo vo = new DailyRespVo();
        String monthly = null;
        if (one.isMonthly()) {
            List<WorkContactDailyEntity> contactEntity = workContactDailyService.lambdaQuery().eq(WorkContactDailyEntity::getCorpId, corpId)
                    .eq(WorkContactDailyEntity::getDailyType, 3)
                    .orderByDesc(WorkContactDailyEntity::getCreateTime).last("limit 1").list();
            if (contactEntity.size() == 0) {
                R<String> ok= R.ok("");
                return ok;
            }

            WorkContactDailyEntity contact = contactEntity.get(0);

            WorkContactRoomDailyEntity room = workContactRoomDailyService.lambdaQuery().eq(WorkContactRoomDailyEntity::getCorpId, corpId)
                    .eq(WorkContactRoomDailyEntity::getDailyType, 3)
                    .orderByDesc(WorkContactRoomDailyEntity::getCreateTime).last("limit 1").list().get(0);
            generate(one,contact, room, vo, 3);
            monthly = change(vo, 3);
        }
        R<String> ok = R.ok(monthly);
        return ok;
    }

    @Override
    public R sendContext(DailySendDTO dto) {
        boolean b = workDailySendService.updateSend(dto);
        return b ? R.ok("更新成功") : R.failed("更新失败");
    }

    @Override
    public DailyIndexVo dailyIndex(Integer type) {

        Integer corpId = CorpContextHolder.getCorpId1();
        LocalDate localDate;

        if (type == 1) {
            localDate = LocalDate.now();
        } else if (type == 2) {
            DateTime dateTime = DateUtil.beginOfWeek(new Date());
            localDate = DateUtil.toLocalDateTime(dateTime).toLocalDate();
        } else {
            DateTime dateTime = DateUtil.beginOfMonth(new Date());
            localDate = DateUtil.toLocalDateTime(dateTime).toLocalDate();
        }
        Integer totalEmployee1 = workEmployeeService.lambdaQuery().eq(WorkEmployeeEntity::getCorpId, corpId)
                .count();
        Integer totalEmployeeContact2 = workContactEmployeeService.lambdaQuery().eq(WorkContactEmployeeEntity::getCorpId, corpId)
                .count();
        List<Object> roomIds = workRoomService.listObjs(Wrappers.<WorkRoomEntity>lambdaQuery().select(WorkRoomEntity::getId).eq(WorkRoomEntity::getRoomStatus, 0).eq(WorkRoomEntity::getCorpId, corpId));
        Integer totalRoom3 = roomIds.size();
        Integer totalRoomContact4;
        Integer addContact5 = workContactEmployeeService.getAddContact(corpId, localDate.toString());
        Integer addRoomContact6;
        if (totalRoom3 != 0) {
            addRoomContact6 = workContactRoomService.getStatistic(localDate, roomIds);
            totalRoomContact4 = workContactRoomService.lambdaQuery().in(WorkContactRoomEntity::getRoomId, roomIds).count();
        } else {
            totalRoomContact4 = 0;
            addRoomContact6 = 0;
        }
        WorkContactDailyEntity dailyEntity = workContactDailyService.getOne(Wrappers.<WorkContactDailyEntity>lambdaQuery()
                .select(WorkContactDailyEntity::getTotalContact)
                .eq(WorkContactDailyEntity::getDailyType, type)
                .eq(WorkContactDailyEntity::getCorpId, corpId)
                .orderByDesc(WorkContactDailyEntity::getCreateTime)
                .last("limit 1"));
        Integer beginContact;
        if (dailyEntity == null) {
            beginContact = 0;
        } else {
            beginContact = dailyEntity.getTotalContact();
        }
        Integer lossEmployeeContact7 = (addContact5 - (totalEmployeeContact2 - beginContact)) < 0 ? 0 : (addContact5 - (totalEmployeeContact2 - beginContact));

        Integer msgNum = workMsgService.getMsgNum(localDate.atStartOfDay(ZoneOffset.systemDefault()).toInstant().toEpochMilli());
        ArrayList<Integer> addEmployeeContacts = new ArrayList<>();
        ArrayList<Integer> lossEmployeeContacts = new ArrayList<>();
        ArrayList<String> dates = new ArrayList<>();
        ArrayList<String> dates1 = new ArrayList<>();
        List<DateTime> detHashList = getDetHashList(localDate.toString(), LocalDate.now().toString());
        if (type != 1) {
            List<WorkContactDailyEntity> list = workContactDailyService.list(Wrappers.<WorkContactDailyEntity>lambdaQuery()
                    .select(WorkContactDailyEntity::getAddContact, WorkContactDailyEntity::getChangeContact, WorkContactDailyEntity::getCreateTime)
                    .eq(WorkContactDailyEntity::getCorpId, corpId)
                    .eq(WorkContactDailyEntity::getDailyType, 1)
                    .ge(WorkContactDailyEntity::getCreateTime, localDate.toString())
                    .orderByAsc(WorkContactDailyEntity::getCreateTime));
            dates = (ArrayList<String>) list.stream().map(m -> m.getCreateTime().toString().substring(0, 10)).collect(Collectors.toList());
            for (int i = 0; i < detHashList.size()-1; i++) {
                Boolean flag = false;
                for (int j = 0; j < dates.size(); j++) {
                    if(detHashList.get(i).toString().substring(0,10).equals(dates.get(j))) {
                        addEmployeeContacts.add(list.get(j).getAddContact());
                        lossEmployeeContacts.add(list.get(j).getAddContact() - list.get(j).getChangeContact());
                        dates1.add(detHashList.get(i).toString().substring(0,10));
                        flag = true;
                    }
                }
                if(flag == false) {
                    addEmployeeContacts.add(i,0);
                    lossEmployeeContacts.add(i,0);
                    dates1.add(detHashList.get(i).toString().substring(0,10));
                }
            }
        }
        addEmployeeContacts.add(addContact5);
        lossEmployeeContacts.add(lossEmployeeContact7);
        dates1.add(LocalDate.now().toString());

        DailyIndexVo vo = new DailyIndexVo(totalEmployee1, totalEmployeeContact2, totalRoom3, totalRoomContact4, msgNum, addContact5, addRoomContact6, lossEmployeeContact7, dates1, addEmployeeContacts, lossEmployeeContacts);
        return vo;
    }

    @Override
    public IPage indexDo(Page page) {
        WorkEmployeeEntity employee = workEmployeeService.getCurrentStatus();
        IPage page1 = employeeDoService.page(page, Wrappers.<EmployeeDoEntity>lambdaQuery().eq(EmployeeDoEntity::getWxUserId, employee.getWxUserId())
                .eq(EmployeeDoEntity::getDoState, 1));
        List collect = (List) page1.getRecords().stream().map(entity -> {
            EmployeeDoVO employeeDoVO = new EmployeeDoVO();
            BeanUtil.copyProperties(entity, employeeDoVO);
            return employeeDoVO;
        }).collect(Collectors.toList());
        page1.setRecords(collect);
        return page1;
    }

    String change(DailyRespVo vo, Integer type) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String typeString = null;
        StringBuffer buffer = new StringBuffer();
        WorkContactDailyIndexResp contact = null;
        WorkContactRoomDailyIndexResp Room = null;
        if (type == 1) {
            contact= vo.getDailyContact();
            Room = vo.getDailyRoom();
            typeString = "昨日";
            buffer.append("【数据日报】\n");
        }
        if (type == 2) {
            contact= vo.getWeekContact();
            Room = vo.getWeekRoom();
            typeString = "上周";
            buffer.append("【数据周报】\n");
        }
        if (type == 3) {
            contact= vo.getMonthContact();
            Room = vo.getMonthRoom();
            typeString = "上个月";
            buffer.append("【数据月报】\n");
        }
        if (!isWorth(contact) && !isWorth(Room)) {
            return "";
        }
        if (isWorth(contact)) {
            buffer.append("客户数据\n");
            if (!Objects.isNull(contact.getTotal())) buffer.append(typeString + "客户总数: " + contact.getTotal() + "\n");
            if (!Objects.isNull(contact.getAddNum())) buffer.append(typeString + "新增客户数: " + contact.getAddNum() + "\n");
            if (!Objects.isNull(contact.getLoss())) buffer.append(typeString + "流失客户数: " + contact.getLoss() + "\n");
            if (!Objects.isNull(contact.getRealAddNum())) buffer.append(typeString + "净增客户数: " + contact.getRealAddNum() + "\n");
            buffer.append("\n\n");
        }
        if (isWorth(Room)) {
            buffer.append("客户群数据\n");
            if (!Objects.isNull(Room.getRoomTotal())) buffer.append(typeString + "客户群数据: " +Room.getRoomTotal() + "\n");
            if (!Objects.isNull(Room.getRoomAddNum())) buffer.append(typeString + "客户群新增数据: " +Room.getRoomAddNum() + "\n");
            if (!Objects.isNull(Room.getContactTotal())) buffer.append(typeString + "群客户总数: " +Room.getContactTotal() + "\n");
            if (!Objects.isNull(Room.getContactAddNum())) buffer.append(typeString + "客户群新增客户数: " +Room.getContactAddNum() + "\n");
            if (!Objects.isNull(Room.getContactLossNum())) buffer.append(typeString + "客户群流失客户数: " +Room.getContactLossNum() + "\n");
            if (!Objects.isNull(Room.getContactRealAddNum())) buffer.append(typeString + "客户群净增客户数: " +Room.getContactRealAddNum() + "\n");
            buffer.append("\n");
        }
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.DAY_OF_YEAR, -1);
        buffer.append("<a href='" + ConstantConfig.getApiUrl() + "/#/statics?dailyDate=" + sdf.format(instance.getTime()) + "&dailyType=" + type + "&cid=" + CorpContextHolder.getCorpId1() + "&tid=" + TenantContextHolder.getTenantId() + "'>点击查看详情</a>");
        return buffer.toString();
    }

    //生成日周月报
    void generate(WorkDailySendEntity one, WorkContactDailyEntity workContactDailyEntity, WorkContactRoomDailyEntity workContactRoomDailyEntity, DailyRespVo vo, Integer type) {
        WorkContactDailyIndexResp workContactDailyIndexResp = new WorkContactDailyIndexResp();
        WorkContactRoomDailyIndexResp workContactRoomDailyIndexResp = new WorkContactRoomDailyIndexResp();
        if (one.isContactChangeContact()) workContactDailyIndexResp.setAddNum(workContactDailyEntity.getChangeContact());
        if (one.isContactLossContact()) workContactDailyIndexResp.setLoss(workContactDailyEntity.getAddContact() - workContactDailyEntity.getChangeContact());
        if (one.isContactRealAddContact()) workContactDailyIndexResp.setRealAddNum(workContactDailyEntity.getRealAddContact());
        if (one.isContactTotalContact()) workContactDailyIndexResp.setTotal(workContactDailyEntity.getTotalContact());

        if (one.isChangeContact()) workContactRoomDailyIndexResp.setContactAddNum(workContactRoomDailyEntity.getChangeContact());
        if (one.isRealAddContact()) workContactRoomDailyIndexResp.setContactRealAddNum(workContactRoomDailyEntity.getRealAddContact());
        if (one.isLossContact()) workContactRoomDailyIndexResp.setContactLossNum(workContactRoomDailyEntity.getAddContact() - workContactRoomDailyEntity.getChangeContact());
        if (one.isTotalContact()) workContactRoomDailyIndexResp.setContactTotal(workContactRoomDailyEntity.getTotalContact());
        if (one.isChangeRoom()) workContactRoomDailyIndexResp.setRoomAddNum(workContactRoomDailyEntity.getChangeRoom());
        if (one.isTotalRoom()) workContactRoomDailyIndexResp.setRoomTotal(workContactRoomDailyEntity.getTotalRoom());
        if (type == 1) {
            vo.setDailyContact(workContactDailyIndexResp);
            vo.setDailyRoom(workContactRoomDailyIndexResp);
        }
        else if (type == 2) {
            vo.setWeekContact(workContactDailyIndexResp);
            vo.setWeekRoom(workContactRoomDailyIndexResp);
        }
        else  {
            vo.setMonthContact(workContactDailyIndexResp);
            vo.setMonthRoom(workContactRoomDailyIndexResp);
        }
    }

    Boolean isWorth(Object obj) {
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field f : fields) {
            Object value = getFieldValueByName(f.getName(), obj);
            if (Objects.isNull(value)) {
                continue;
            }
            if (!StringUtils.isNullOrEmpty(value.toString())) {
                return true;
            }
        }
        return false;
    }

    Object getFieldValueByName(String fieldName, Object o) {
        try {
            String firstLetter = fieldName.substring(0, 1).toUpperCase();
            String getter = "get" + firstLetter + fieldName.substring(1);
            Method method = o.getClass().getMethod(getter, new Class[]{});
            Object value = method.invoke(o, null);
            return value;
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取两个日期中的所有日期,并转换为表后缀
     *
     * @param begin 格式:yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
     * @param end   格式:yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
     * @return 格式:MM_dd
     */
    public static List<DateTime> getDetHashList(String begin, String end) {
        String btime = begin.substring(0, 10);//yyyy-MM-dd
        String etime = end.substring(0, 10);

        Date bDate = DateUtil.parse(btime, DatePattern.NORM_DATE_PATTERN);//yyyy-MM-dd
        Date eDate = DateUtil.parse(etime, DatePattern.NORM_DATE_PATTERN);
        List<DateTime> dateList = DateUtil.rangeToList(bDate, eDate, DateField.DAY_OF_YEAR);//创建日期范围生成器
        return dateList;
    }
}
